/*-------------------------------------------------------------------------
 *
 * dict_ispell.c
 *		Ispell 词典接口
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *	  src/backend/tsearch/dict_ispell.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "commands/defrem.h"
#include "tsearch/dicts/spell.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_utils.h"
#include "utils/builtins.h"


typedef struct
{
	StopList	stoplist;
	IspellDict	obj;
} DictISpell;

Datum dispell_init(PG_FUNCTION_ARGS)
{
	List	   *fc_dictoptions = (List *) PG_GETARG_POINTER(0);
	DictISpell *fc_d;
	bool		fc_affloaded = false,
				fc_dictloaded = false,
				fc_stoploaded = false;
	ListCell   *fc_l;

	fc_d = (DictISpell *) palloc0(sizeof(DictISpell));

	NIStartBuild(&(fc_d->obj));

	foreach(fc_l, fc_dictoptions)
	{
		DefElem    *fc_defel = (DefElem *) lfirst(fc_l);

		if (strcmp(fc_defel->defname, "dictfile") == 0)
		{
			if (fc_dictloaded)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("multiple DictFile parameters")));
			NIImportDictionary(&(fc_d->obj),
							   get_tsearch_config_filename(defGetString(fc_defel),
														   "dict"));
			fc_dictloaded = true;
		}
		else if (strcmp(fc_defel->defname, "afffile") == 0)
		{
			if (fc_affloaded)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("multiple AffFile parameters")));
			NIImportAffixes(&(fc_d->obj),
							get_tsearch_config_filename(defGetString(fc_defel),
														"affix"));
			fc_affloaded = true;
		}
		else if (strcmp(fc_defel->defname, "stopwords") == 0)
		{
			if (fc_stoploaded)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("multiple StopWords parameters")));
			readstoplist(defGetString(fc_defel), &(fc_d->stoplist), lowerstr);
			fc_stoploaded = true;
		}
		else
		{
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("unrecognized Ispell parameter: \"%s\"",
							fc_defel->defname)));
		}
	}

	if (fc_affloaded && fc_dictloaded)
	{
		NISortDictionary(&(fc_d->obj));
		NISortAffixes(&(fc_d->obj));
	}
	else if (!fc_affloaded)
	{
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("missing AffFile parameter")));
	}
	else
	{
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("missing DictFile parameter")));
	}

	NIFinishBuild(&(fc_d->obj));

	PG_RETURN_POINTER(fc_d);
}

Datum dispell_lexize(PG_FUNCTION_ARGS)
{
	DictISpell *fc_d = (DictISpell *) PG_GETARG_POINTER(0);
	char	   *fc_in = (char *) PG_GETARG_POINTER(1);
	int32		fc_len = PG_GETARG_INT32(2);
	char	   *fc_txt;
	TSLexeme   *fc_res;
	TSLexeme   *fc_ptr,
			   *fc_cptr;

	if (fc_len <= 0)
		PG_RETURN_POINTER(NULL);

	fc_txt = lowerstr_with_len(fc_in, fc_len);
	fc_res = NINormalizeWord(&(fc_d->obj), fc_txt);

	if (fc_res == NULL)
		PG_RETURN_POINTER(NULL);

	fc_cptr = fc_res;
	for (fc_ptr = fc_cptr; fc_ptr->lexeme; fc_ptr++)
	{
		if (searchstoplist(&(fc_d->stoplist), fc_ptr->lexeme))
		{
			pfree(fc_ptr->lexeme);
			fc_ptr->lexeme = NULL;
		}
		else
		{
			if (fc_cptr != fc_ptr)
				memcpy(fc_cptr, fc_ptr, sizeof(TSLexeme));
			fc_cptr++;
		}
	}
	fc_cptr->lexeme = NULL;

	PG_RETURN_POINTER(fc_res);
}
